package org.microser.gataway.zuul.filter;

import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.microser.gataway.zuul.config.SecurityFilter;
import org.microser.gataway.zuul.system.entity.Permission;
import org.microser.gataway.zuul.system.entity.Role;
import org.microser.gataway.zuul.system.service.PermissionService;
import org.microser.gataway.zuul.system.service.RoleService;
import org.microser.gataway.zuul.utils.MatchingURI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 需要登录过滤器
 *
 * @author liujiamiao
 * @email 2544296058@qq.com
 * @date 2020-11-17 9:09
 */
@Slf4j
public class JwtFilter extends DefinedZuulFilter {

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SecurityFilter securityFilter;

    @Override
    public String filterType() {
        return FILTERTYPE_PRE;
    }

    public void error(HttpServletRequest request,String msg,int code){
        request.setAttribute("msg",msg);
        request.setAttribute("code",code);
        throw new RuntimeException(request.getAttribute("msg").toString());
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext currentContext = RequestContext.getCurrentContext();
        //获取request对象
        HttpServletRequest request = currentContext.getRequest();

        log.warn("登录过滤 = "+request.getRequestURI());

        //遍历cookie
//        System.out.println("cookie :");
//        Cookie[] cookies = request.getCookies();
//        if(cookies!=null&&cookies.length>0){
//            for(Cookie cookie : cookies){
//                System.out.println(cookie.getName()+":"+cookie.getValue());
//            }
//        }

        //是否带了uuid_token --- 旧写法，原本是带uuid的，现在是bearerToken
//        String uuid = request.getHeader(DefContants.UUID_TOKEN);
//        if(StringUtils.isEmpty(uuid)){
//            error(request,"不存在token，请前往登录",401);
//        }
//        //token存在则从redis中获取token值，是否存在
//        String token = String.valueOf(redisTemplate.opsForValue().get(uuid));
//        if(StringUtils.isEmpty(token)){
//            //redis中不存在，则抛出异常，token超时，重新登录
//            error(request,"token超时，请重新登录",401);
//        }

        //获取bearer token 方法
        String auth = request.getHeader("Authorization");
        if (!StringUtils.isEmpty(auth) && auth.indexOf("Bearer") >= 0) {
            auth = auth.substring("Bearer ".length(), auth.length());
        }else{
            error(request,"token超时，请重新登录",401);
        }
        //token存在则从redis中获取token值，是否存在
        String bearerToken = String.valueOf(redisTemplate.opsForValue().get(auth));
        if(StringUtils.isEmpty(bearerToken)||bearerToken.equals("null")){
            //redis中不存在，则抛出异常，token超时，重新登录
            error(request,"token超时，请重新登录",401);
        }

        //准备替换的header信息  --- 本地修改了request，但目标服务器并没有修改，因此，该方法无效
//        Map<String,String> headerses = new HashMap<>();
//        //遍历header信息
//        Enumeration<String> headerNames = request.getHeaderNames();
//        while (headerNames.hasMoreElements()){
//            String name = headerNames.nextElement();
//            //如果是Authorization（token）则特殊处理
//            if(name.equals("Authorization")){
//                headerses.put("Authorization","Bearer "+bearerToken);
//            }else{
//                headerses.put(name,request.getHeader(name));
//            }
//        }
//        MatchingURI.modifyHeaders(request,headerses);


        //更新token的有效时间
        redisTemplate.opsForValue().set(auth,bearerToken);
        redisTemplate.expire(auth, 30 * 60 * 1000, TimeUnit.SECONDS);

        //接下来就是获取权限了
        //获取角色
        List<Role> roles = roleService.queryRoleListByUserId("1");
        //角色获取权限列表
        List<Permission> permissions = permissionService.permissions(roles);
        //权限值
        List<String> permissionValue = permissionService.permissionValue(permissions);


        //权限遍历是否有该资源
        //获取请求uri
        String requestURI = request.getRequestURI();
        //得到所有需要权限的uri
        LinkedHashMap<String, String> securityPath = securityFilter.securityPath();
        //遍历uri
        for(Map.Entry<String,String> entry : securityPath.entrySet()){
            //匹配到本次访问的uri
            if(MatchingURI.equlasUri(entry.getKey(),requestURI)){
                System.out.println("该uri需要权限"+requestURI);
                //该uri可能存在多添加，条件之间用“，”隔开   这里存在文件，
                // 如果用户些的权限值是：admin, Roles[a,b,c], user:add，那么将会把Roles里面的角色都拆分出来
//                String[] split = entry.getValue().split(",");
                String[] split = MatchingURI.split(entry.getValue());
                System.out.println(Arrays.toString(split));
                //目的是如果是 或者（||），只要完成一个即可
                boolean[] flag = new boolean[split.length];
                boolean[] result = new boolean[flag.length];
                for(int i = 0;i<split.length;i++){
                    String permission = split[i];
                    //说明条件是 或者
                    if(permission.indexOf("()")!=-1){
                        flag[i] = true;
                        int temp = permission.indexOf("()");
                        permission = permission.substring(0,temp);
                    }

                    //上一个已经是true了，这个不需要判断了
                    if(i>0&&flag[i-1]&&result[i-1]){
                        result[i] = result[i-1];
                        continue;
                    }
                    System.out.println(permission);
                    if(permission.indexOf("roles[")!=-1&&permission.indexOf("]")!=-1){
                        //单个条件中可能需要某个角色
                        permission = permission.substring(permission.indexOf("roles[")+6,permission.indexOf("]"));

                        //角色列表中可能有多个角色，再次用都好隔开
                        String[] rolePermission = permission.split(",");
                        for(String roleP : rolePermission){
                            if(!MatchingURI.includeRole(roleP,roles)){
                                //该字段是或者，继续判断下一个权限
                                System.out.println("角色条件为 false");
                                if(flag[i]){
                                    continue;
                                }
                                error(request,"用户权限不足",403);
                            }
                            System.out.println("角色条件为 true");
                            result[i] = true;
                        }
                    }else {
                        //不是角色，就是权限
                        if(!MatchingURI.includePermission(permission,permissionValue)){
                            //该字段是或者，继续判断下一个权限
                            System.out.println("权限条件为 false");
                            if(flag[i]){
                                continue;
                            }
                            error(request,"用户权限不足",403);
                        }
                        System.out.println("权限条件为 true");
                        result[i] = true;
                    }
                }
                return true;
            }
        }

        //---是放行，还是进一度判断？

        //token获取用户名？
            //用户名为空抛出异常

        //用户名读取数据库账号
            //为空抛异常

        //判断用户状态
            //不为1抛出异常
        return true;
    }


}
